
/*
LucidObserver.prototype = {
    subscribe : function(fn) {
        this.fns.push(fn);
    },
    unsubscribe : function(fn) {
        this.fns = this.fns.filter(
            function(el) {
                if ( el !== fn ) {
                    return el;
                }
            }
        );
    },
    fire : function(o, thisObj) {
        var scope = thisObj || window;
        this.fns.forEach(
            function(el) {
                el.call(scope, o);
            }
        );
    },
    initialize: function()
    {
        this.fns = [];
    }
}
*/


if ( !Array.prototype.forEach ) {
	Array.prototype.forEach = function(fn, thisObj) {
				var scope = thisObj || window;
				for ( var i=0, j=this.length; i < j; ++i ) {
					fn.call(scope, this[i], i, this);
				}
			}

        Array.prototype.every =
			function(fn, thisObj) {
				var scope = thisObj || window;
				for ( var i=0, j=this.length; i < j; ++i ) {
					if ( !fn.call(scope, this[i], i, this) ) {
						return false;
					}
				}
				return true;
			}
		Array.prototype.some =
			function(fn, thisObj) {
			    var scope = thisObj || window;
				for ( var i=0, j=this.length; i < j; ++i ) {
			        if ( fn.call(scope, this[i], i, this) ) {
			            return true;
			        }
			    }
			    return false;
			}
		Array.prototype.map =
			function(fn, thisObj) {
			    var scope = thisObj || window;
			    var a = [];
			    for ( var i=0, j=this.length; i < j; ++i ) {
			        a.push(fn.call(scope, this[i], i, this));
			    }
			    return a;
			}
		Array.prototype.filter =
			function(fn, thisObj) {
			    var scope = thisObj || window;
			    var a = [];
			    for ( var i=0, j=this.length; i < j; ++i ) {
			        if ( !fn.call(scope, this[i], i, this) ) {
			            continue;
			        }
			        a.push(this[i]);
			    }
			    return a;
			}
		Array.prototype.indexOf =
			function(el, start) {
			    start = start || 0;
			    for ( var i=start, j=this.length; i < j; ++i ) {
			        if ( this[i] === el ) {
			            return i;
			        }
			    }
			    return -1;
			}
		Array.prototype.lastIndexOf =
			function(el, start) {
			    start = start || this.length;
			    if ( start >= this.length ) {
			        start = this.length;
			    }
			    if ( start < 0 ) {
			         start = this.length + start;
			    }
			    for ( var i=start; i >= 0; --i ) {
			        if ( this[i] === el ) {
			            return i;
			        }
			    }
			    return -1;
			}

}
window.openDialog = function() {};
window.content = {
    gmonkey: {}
};
window.gBrowser = {
};

Event.prototype.originalTarget = {};

function GmailAPI()
{
    this.getActiveViewType = function(){};
    this.getActiveViewElement = function(){};
    this.registerViewChangeCallback = function(){};
    this.addNavModule = function(){};
    this.getNavPaneElement = function(){};
}

function GmailNavBox()
{
    this.setContent = function(){};
}

document.getAnonymousNodes = function() {};

document.commandDispatcher = {
    focusedElement: {}
}

Error.prototype.fileName = "";
Error.prototype.stack = "";

var Components = {
    classes: [],
    results: {},
    Constructor: function() {},
    ID: function(){}
};

Components.interfaces = {
    nsILucidService: {},
    nsISupportsString: {},
    mozIJSSubScriptLoader: {}
};

Components.utils = {
    import: function() {},
    reportError: function() {}
};

function getBrowser() {};
function sizeToContent() {};

function JSON() {
    this.fromString = function(){};
};


function XpcomComponent() {
    this.equals = function(){};
};


function StringBundle() {
    this.getString = function(){};
};

function ListBox() {
    this.addItemToSelection = function() {};
    this.removeItemAt = function() {};
    this.selectedItems = [];
    this.selectedItem = {};
    this.appendItem = function() {};
    this.selectItem = function() {};
};

function KeyList() {
    this.tree = function() {};
};

function TreeThing() {
    this.treeBoxObject = function() {};
    this.scrollToRow = function() {};    
    this.getFirstVisibleRow = function() {};
    this.getPrimaryColumn = function() {};
    this.columns = {};
}

function MenulistElement() {
    this.removeAllItems = function() {};
};

function nsISupports() {
};

Components.interfaces.nsITreeSelection = function()
{
    this.currentIndex = function() {};
}

Components.interfaces.nsILocaleService = function()
{
    this.getApplicationLocale = function() {};
}

Components.interfaces.nsIStringBundleService = function()
{
    this.createBundle = function() {};
}

Components.interfaces.nsIStringBundle = function()
{
    this.GetStringFromName = function() {};
    this.formatStringFromName = function() {};
}

Components.interfaces.nsIFile = function()
{
}

Components.interfaces.nsITreeBoxObject = function()
{
    this.getCellAt = function() {};
}

Components.interfaces.nsICollection = function()
{
    this.Count = function() {};
    this.GetElementAt = function() {};    
}

Components.interfaces.nsISupportsArray = function()
{
    this.AppendElement = function() {};
}

Components.interfaces.nsIExtensionManager = function()
{
    this.getItemForID = function() {};
}

Components.interfaces.nsIIOService = function()
{
    this.newURI = function() {};
}

Components.interfaces.nsIRDFDataSource = function()
{
//    this.getItemForID = function() {};
}

Components.interfaces.nsIRDFXMLParser = function()
{
    this.parseString = function() {};
}

function nsIClipboard() {
    this.getData = function() {};
    this.kGlobalClipboard = {};
};

function nsIClipboardHelper() {
    this.copyString = function() {};
};

function nsITransferable() {
    this.addDataFlavor = function() {};
    this.getTransferData = function() {};
};

Components.interfaces.nsIPrefService = function()
{
    this.getBranch = function() {};
};

Components.interfaces.nsIPrefBranch = function()
{
    this.setIntPref = function() {};
    this.setBoolPref = function() {};
    this.setCharPref = function() {};
    this.getPrefType = function() {};
    this.getBoolPref = function() {};
    this.getIntPref = function() {};
    this.getCharPref = function() {};
    this.PREF_BOOL = 0;
    this.PREF_INT = 0;
    this.PREF_STRING = 0;

    // 2

    this.addObserver = function() {};
    this.removeObserver = function() {};
    this.notifyObservers = function() {};
};

Components.interfaces.nsIPrefBranch2 = Components.interfaces.nsIPrefBranch;

Components.interfaces.nsIDOMWindow = function() {
    this.getBrowser = function() {};
};

// Does this really exist?
Components.interfaces.nsIBrowser = function() {
    this.addTab = function() {};
};

Components.interfaces.nsIWindowWatcher = function() {
    this.openWindow = function() {};
};

Components.interfaces.nsIWindowMediator = function() {
    this.getMostRecentWindow = function() {};
};

Components.interfaces.nsILoginManager = function() {
    this.findLogins = function() {};
};

Components.interfaces.nsILoginInfo = function() {
    this.username = "foo";
    this.password = "foo";
};

function mozIJSSubScriptLoader() {
    this.loadSubScript = function() {};
};

Components.interfaces.nsIPromptService = function()
{
    this.promptPassword = function() {};
};

Components.interfaces.nsIConsoleService = function()
{
    this.logMessage = function() {};
    this.logStringMessage = function() {};
};

Components.interfaces.nsIScriptError = function()
{
};

Components.interfaces.nsIDOMJSWindow = function()
{
};

Components.interfaces.nsIMutableArray = function()
{
    this.appendElement = function() {};
};

Components.interfaces.nsIThread = function()
{
    this.adjustPriority = function() {};
    this.dispatch = function() {};
    this.DISPATCH_NORMAL = 1;
};

Components.interfaces.nsIThreadManager = function()
{
    this.newThread = function() {};
    this.isMainThread = function() {};
    this.mainThread = {};
};

Components.interfaces.nsILocalFile = function()
{
    this.initWithPath = function() {};
    this.appendRelativePath = function() {};
    this.exists = function() {};
    this.path = "";
    this.create = function() {};
    this.CLOSE_ON_EOF = 0;
    this.DIRECTORY_TYPE = 0;
};

Components.interfaces.nsIInputStream = function()
{
    this.init = function() {};
    this.read = function() {};
    this.setInputStream = function() {};
    this.readBytes = function() {};
    this.readString = function() {};
};

Components.interfaces.nsIOuputStream = function()
{
    this.writeBytes = function() {};
    this.writeString = function() {};
    this.setOutputStream = function() {};
};

Components.interfaces.nsIXULRuntime = function()
{
    this.OS = "";
};

Components.interfaces.nsIProperties = function()
{
    this.get = function(){};
};

Components.interfaces.nsIFilePicker = function()
{
    this.file = {};
    this.show = function() {};
    this.appendFilters = function() {};
    this.modeOpen = 0;
    this.modeSave = 0;
    this.filterText = 0;
    this.returnReplace = 0;
    this.modeGetFolder = 0;
    this.filterAll = 0;
    this.returnOK = 0;
};

function nsIIOService() {
    this.newChannel = function() {};
};

function Channel() {
    this.available = function() {};
};

function FooBar() {
    this.getService = function() {};
    this.createInstance = function() {};
}

/*
    loadScript: function( scripts, context )
    {
        if (typeof(scripts) == "string")
        {
            scripts = [scripts];
        }
        var baseLoader = Components.classes['@mozilla.org/moz/jssubscript-loader;1']
            .getService(Components.interfaces["mozIJSSubScriptLoader"]);
        var retval = undefined;
        for (var ii = 0; ii < scripts.length; ii++)
        {
            retval = baseLoader.loadSubScript('chrome://lucidity/content/' + scripts[ii], context);
        }
        return retval;
    }

gLucidBrowser.loadScript([
    "foobar.js"
], gLucidBrowser);
*/

/*
function lucid_typeof( vExpression )
{
    var sTypeOf = typeof vExpression;
    if (sTypeOf == "function")
    {
        var sFunction = vExpression.toString();
        if (( /^\/.*\/$/ ).test(sFunction))
        {
            return "regexp";
        }
        else if (( /^\[object.*\]$/i ).test(sFunction))
        {
            sTypeOf = "object"
        }
    }
    if (sTypeOf != "object")
    {
        return sTypeOf;
    }

    switch (vExpression) {
        case null:
            return "null";

//
//        case window:
//            return "window";
//        case window.event:
//            return "event";
//

    }

//    if (window.event && ( event.type == vExpression.type ))
//    {
//        return "event";
//    }

    var fConstructor = vExpression.constructor;
    if (fConstructor != null)
    {
        switch (fConstructor) {
            case Array:
                sTypeOf = "array";
                break;
            case Date:
                return "date";
            case RegExp:
                return "regexp";
            case Object:
                sTypeOf = "jsobject";
                break;
            case ReferenceError:
                return "error";
            default:
                var sConstructor = fConstructor.toString();
                var aMatch = sConstructor.match(/\s*function (.*)\(/);
                if (aMatch != null)
                {
                    return aMatch[ 1 ];
                }
        }
    }

    var nNodeType = vExpression.nodeType;
    if (nNodeType != null)
    {
        switch (nNodeType) {
            case 1:
                if (vExpression.item == null)
                {
                    return "domelement";
                }
                break;
            case 3:
                return "textnode";
        }
    }

    if (vExpression.toString != null)
    {
        var sExpression = vExpression.toString();
        var bMatch = sExpression.match(/^\[object (.*)\]$/i);
        if (bMatch != null)
        {
            var sMatch = bMatch[ 1 ];
            switch (sMatch.toLowerCase()) {
                case "event":
                    return "event";
                case "math":
                    return "math";
                case "error":
                    return "error";
                case "mimetypearray":
                    return "mimetypecollection";
                case "pluginarray":
                    return "plugincollection";
                case "windowcollection":
                    return "window";
                case "nodelist":
                case "htmlcollection":
                case "elementarray":
                    return "domcollection";
            }
        }
    }

    if (vExpression.moveToBookmark && vExpression.moveToElementText)
    {
        return "textrange";
    }
    else if (vExpression.callee != null)
    {
        return "arguments";
    }
    else if (vExpression.item != null)
    {
        return "domcollection";
    }

    return sTypeOf;
}

var HTMLFormatter = lucidapi.AbstractClass.extend(function(classref) {

    function objectToString(object)
    {
        try
        {
            return object+"";
        }
        catch (exc)
        {
            return null;
        }
    }

    function appendText(object, html)
    {
        html.push(lucidapi.escapeEntities(objectToString(object)));
    }

    function appendNull(object, html)
    {
        html.push('<span class="objectBox-null">', lucidapi.escapeEntities(objectToString(object)), '</span>');
    }

    function appendString(object, html)
    {
        html.push('<span class="objectBox-string">&quot;', lucidapi.escapeEntities(objectToString(object)),
            '&quot;</span>');
    }

    function appendInteger(object, html)
    {
//        html.push('<span class="objectBox-number">', lucidapi.escapeEntities(objectToString(object)), '</span>');
        html.push('', lucidapi.escapeEntities(objectToString(object)), '');
    }

    function appendFloat(object, html)
    {
        html.push('<span class="objectBox-number">', lucidapi.escapeEntities(objectToString(object)), '</span>');
    }

    function appendFunction(object, html)
    {
        var reName = /function ?(.*?)\(/;
        var m = reName.exec(objectToString(object));
        var name = m ? m[1] : "function";
        html.push('<span class="objectBox-function">', lucidapi.escapeEntities(name), '()</span>');
    }

    function appendObjectFormatted(object, html)
    {
        var text = objectToString(object);
        var reObject = /\[object (.*?)\]/;

        var m = reObject.exec(text);
        html.push('<span class="objectBox-object">', m ? m[1] : text, '</span>')
    }

    function appendSelector(object, html)
    {
        html.push('<span class="objectBox-selector">');

        html.push('<span class="selectorTag">', lucidapi.escapeEntities(object.nodeName.toLowerCase()), '</span>');
        if (object.id)
            html.push('<span class="selectorId">#', lucidapi.escapeEntities(object.id), '</span>');
        if (object.className)
            html.push('<span class="selectorClass">.', lucidapi.escapeEntities(object.className), '</span>');

        html.push('</span>');
    }

    function appendObject(object, html)
    {
        try
        {
            if (object == undefined)
                appendNull("undefined", html);
            else if (object == null)
                appendNull("null", html);
            else if (typeof object == "string")
                appendString(object, html);
            else if (typeof object == "number")
                appendInteger(object, html);
            else if (typeof object == "function")
                appendFunction(object, html);
            else if (object.nodeType == 1)
                appendSelector(object, html);
            else if (typeof object == "object")
                appendObjectFormatted(object, html);
            else
                appendText(object, html);
        }
        catch (exc)
        {
        }
    }

    function parseFormat(format)
    {
        var parts = [];

        var reg = /((^%|[^\\]%)(\d+)?(\.)([a-zA-Z]))|((^%|[^\\]%)([a-zA-Z]))/;
        var appenderMap = {s: appendText, d: appendInteger, i: appendInteger, f: appendFloat};

        for (var m = reg.exec(format); m; m = reg.exec(format))
        {
            var type = m[8] ? m[8] : m[5];
            var appender = type in appenderMap ? appenderMap[type] : appendObject;
            var precision = m[3] ? parseInt(m[3]) : (m[4] == "." ? -1 : 0);

            parts.push(format.substr(0, m[0][0] == "%" ? m.index : m.index+1));
            parts.push({appender: appender, precision: precision});

            format = format.substr(m.index+m[0].length);
        }

        parts.push(format);

        return parts;
    }

    function logRow(message, className)
    {
        return message.join("");
    }

    return {
        initialize: function() {
            classref.superClass.initialize.call(this);
        },
        logFormatted: function(objects, className) {
            var html = [];

            var format = objects[0];
            var objIndex = 0;
            var object;
            var i;
            if (typeof(format) != "string")
            {
                format = "";
                objIndex = -1;
            }

            var parts = parseFormat(format);
            for (i = 0; i < parts.length; ++i)
            {
                var part = parts[i];
                if (part && typeof(part) == "object")
                {
                    object = objects[++objIndex];
                    part.appender(object, html);
                }
                else
                    appendText(part, html);
            }

            for (i = objIndex+1; i < objects.length; ++i)
            {
                appendText(" ", html);

                object = objects[i];
                if (typeof(object) == "string")
                    appendText(object, html);
                else
                    appendObject(object, html);
            }

            return logRow(html, className);
        }
    }
});
*/
